/*--------------------------------------------------------------------------------------*\
**
** adv_border_guard.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "adv_border_guard.h"

#include <stack>
#include "adaptor_handler.h"
#include "adventure_frame.h"
#include "adventure_map.h"
#include "adventure_sounds.h"
#include "adv_object_model.h"
#include "adv_object_strings.h"
#include "adv_object_type.h"
#include "army.h"
#include "basic_dialog.h"
#include "creature.h"
#include "creature_type.h"
#include "enum_operations.h"
#include "hero.h"
#include "music.h"
#include "object_registration.h"
#include "player.h"
#include "replace_keywords.h"
#include "simple_dialog.h"

static t_register_with_type<t_adv_border_guard> k_registration( k_adv_object_border_guard );

float const k_ai_value_of_border_guard = 1500.0f;

/*
** Adventure border guard constructor.
*/
t_adv_border_guard::t_adv_border_guard (  std::string const& source, 
										  t_qualified_adv_object_type const& type )
         : t_stationary_adventure_object( source )
{
    // Get major subtype (flag color).
    m_major_subtype = type.major_subtype();
}

void t_adv_border_guard::activate_trigger( t_army* army, t_adv_map_point const& point, 
          t_direction direction, t_adventure_frame* frame )
{
	t_player* player = army->get_owner();
	if (player == NULL)
		return;

	bool has_key = player->has_key( m_major_subtype );
	
	if (player->is_computer())
	{
		if (has_key)
		{
	        remove_chains( *this );
		    destroy();
		}
		return;
	}
    
	/*
    ** Check if player has key.
    */
    if (!has_key)
    {
		std::string     denied_text;
	    std::string     object_text;
        t_basic_dialog* denied_dialog_ptr;
        
        object_text = ::get_name ( t_qualified_adv_object_type (k_adv_object_keymaster_tent, m_major_subtype) );

    	denied_text = replace_keywords( get_text( "Denied" ), "%keymaster_tent_name", object_text );
        denied_dialog_ptr = new t_basic_dialog;
        denied_dialog_ptr->set_text( denied_text );

        denied_dialog_ptr->add_ok_button();
        denied_dialog_ptr->open( get_dialog_bottom( point ), true, k_align_bottom );
		t_sound_cache music = get_music_playing();
		stop_music();
		get_dialog_sound( k_dialog_sound_quest )->play( get_sound_volume() );
        denied_dialog_ptr->run_modal();
		play_music( music );
    
        return;
    }

    // Give player option of removing guard.
    t_basic_dialog* result_dialog_ptr;

    result_dialog_ptr = new t_basic_dialog;
    result_dialog_ptr->set_text( get_text ("Accepted") );

    result_dialog_ptr->add_cancel_button();
    result_dialog_ptr->add_ok_button();
    result_dialog_ptr->open( get_dialog_bottom( point ), true, k_align_bottom );

    // Remove guard?
	t_sound_cache music = get_music_playing();
	stop_music();
	get_dialog_sound( k_dialog_sound_quest )->play( get_sound_volume() );
    if (result_dialog_ptr->run_modal())
    {
        // Remove adjacent chains.
        remove_chains( *this );

        // Remove guard. 
	    destroy();
    }
	play_music( music );

    //frame->update();
}

// Remove adjacent chains.
void remove_chains( t_adventure_object& first_object )
{
    /*
    ** Find all adjacent chain links and remove them as well.
    */
	t_adventure_map*        map_ptr = first_object.get_map();
    t_level_map_point_2d	origin;
	t_level_map_point_2d    map_point;
    t_map_point_2d			footprint_size;
    t_map_point_2d			offset;
	std::list<t_adventure_object_ptr>	objects;

    // Init stack with border guard.
	objects.push_back( &first_object );

    // More to check?
    while (!objects.empty())
    {
        // Pop stack.
		origin = objects.back()->get_position();
		footprint_size = objects.back()->get_footprint().get_size();
		objects.pop_back();

        // Check if adjacent tiles have chains.
	    for (offset.row = -1; offset.row <= footprint_size.row; offset.row++)
    	{
    		for (offset.column = -1; offset.column <= footprint_size.column; offset.column++)
    		{
				// skip corners.
				if ((offset.row == -1 || offset.row == footprint_size.row)
					&& (offset.column == -1 || offset.column == footprint_size.column))
					continue;

    			map_point = origin + offset;
				if ( !map_ptr->is_valid( map_point ) )
        			continue;
                
                t_adventure_tile const& map_tile = map_ptr->get_adv_tile( map_point );

                // Get number of objects intersecting tile.
				int num_object_count = map_tile.get_intersecting_object_count();

                // Any intersecting objects?
                while (num_object_count--)
                {
	                t_adventure_map_object_id obj_id 
						= map_tile.get_intersecting_object_id( num_object_count );

	                t_adventure_object*	object = &map_ptr->get_adv_object( obj_id );
                    t_stationary_adventure_object* stationary_object = 
                            dynamic_cast<t_stationary_adventure_object *> (object);

                    // Check if it's a chain.  If so, remove it.
                    if (stationary_object == 0)
						continue;

                    if (stationary_object->get_type().get() == k_adv_object_chain)
                    {
                        // Push chain to stack to be checked.
						objects.push_back( stationary_object );
                        stationary_object->destroy();
                    }
                }
    		}
        }
	}
}

// -------------------------------------------------------------
// For compatibility.
// -------------------------------------------------------------
bool t_adv_border_guard::write( std::streambuf& stream ) const
{
	put<int>( stream, 0 );
	return true;
}

// -------------------------------------------------------------
// For compatibility.
// -------------------------------------------------------------
bool t_adv_border_guard::read( std::streambuf&						stream, 
							   t_qualified_adv_object_type const&	type,
							   int									version )

{
	int single_use_id = get<int>( stream );
	return true;
}

// -------------------------------------------------------------
// -------------------------------------------------------------
float t_adv_border_guard::ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const
{
	if (army.get_owner()->has_key( m_major_subtype ))
		return k_ai_value_of_border_guard;
	else
		return 0.0f;
}
